package com.bing.dao.impl;

import com.bing.dao.BaseDao;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;

/**
 * Created by kaibb on 15-11-28.
 */
public abstract class BaseDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {
    private final Class<T> clazz;

    public BaseDaoImpl() {
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        clazz = (Class<T>) type.getActualTypeArguments()[0];
    }

    @Autowired
    private SessionFactory sessionFactory;

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    @Override
    public PK save(T entity) {
        return (PK) getSession().save(entity);
    }

    @Override
    public T merger(T entity) {
        return (T) getSession().merge(entity);
    }

    @Override
    public void update(T entity) {
        getSession().update(entity);
    }

    @Override
    public void delete(T entity) {
        getSession().delete(entity);
    }

    @Override
    public void delete(PK pk) {
        getSession().delete(findById(pk));
    }

    @Override
    public T findById(PK id) {
        return getSession().get(clazz, id);
    }

    @Override
    public List<T> findByPage(int pageNo, int pageSize, String hql, Map<String, Object> params) {
        Query query = getQuery(hql, params);
        query.setMaxResults(pageSize);
        query.setFirstResult((pageNo - 1) * pageSize);
        return query.list();
    }

    @Override
    public T findFirst(String hql, Map<String, Object> params) {
        Query query = getQuery(hql, params);
        query.setMaxResults(1);
        return (T) query.uniqueResult();
    }

    @Override
    public List findBySQL(int page, int pageSize, String sql, Map<String, Object> params) {
        SQLQuery sqlQuery = getSQLQuery(sql, params);
        sqlQuery.setFirstResult((page - 1) * pageSize);
        sqlQuery.setMaxResults(pageSize);
        return sqlQuery.list();
    }

    @Override
    public List<T> findByHQL(String hql, Map<String, Object> params) {
        Query query = getQuery(hql, params);
        return query.list();
    }

    @Override
    public Object findByHQLOne(String hql, Map<String, Object> params) {
        Query query = getQuery(hql, params);
        return query.uniqueResult();
    }

    private Query getQuery(String hql, Map<String, Object> params) {
        Query query = this.getSession().createQuery(hql);
        query.setProperties(params);
        return query;
    }

    private SQLQuery getSQLQuery(String sql, Map<String, Object> params) {
        SQLQuery query = this.getSession().createSQLQuery(sql);
        query.setProperties(params);
        return query;
    }
}
